use chrono::Local;
use quic_secs_driver::{
    enums::{ConnectionStatus, LogLevel},
    secs2::MessageWrapperForReceived,
};
use serde::Serialize;

use crate::helper;

#[derive(serde::Deserialize, serde::Serialize, Clone)]
pub(crate) struct ConnectionOptions {
    #[serde(rename = "identity")]
    pub(crate) identity: String,

    /// 0 Secs1
    ///
    /// 1 HSMS
    pub(crate) protocol: u8,

    #[serde(rename = "systemByte")]
    pub(crate) system_byte: u32,

    #[serde(rename = "deviceId")]
    pub(crate) device_id: u16,

    #[allow(dead_code)]
    pub(crate) secs1: Option<Secs1Otptions>,
    pub(crate) hsms: Option<HSMSOtptions>,
}

impl Default for ConnectionOptions {
    fn default() -> Self {
        Self {
            identity: String::new(),
            protocol: 0,
            device_id: 0,
            secs1: None,
            hsms: None,
            system_byte: 0,
        }
    }
}

#[allow(dead_code)]
#[derive(serde::Deserialize, serde::Serialize, Clone)]
pub(crate) struct Secs1Otptions {
    mode: u8,
    com: String,

    #[serde(rename = "baudRate")]
    baud_rate: u16,
    ip: String,
    port: u16,
    t1: u64,
    t2: u64,
    t3: u64,
    t4: u64,
    retry: u16,

    #[serde(rename = "isInterleave")]
    is_interleave: bool,

    #[serde(rename = "isMaster")]
    is_master: bool,
}

#[derive(serde::Deserialize, serde::Serialize, Clone)]
pub(crate) struct HSMSOtptions {
    /// 0 active
    /// 1 passive
    pub(crate) mode: u8,

    #[serde(rename = "localIp")]
    pub(crate) local_ip: String,

    #[serde(rename = "localPort")]
    pub(crate) local_port: u16,

    #[serde(rename = "remoteIp")]
    pub(crate) remote_ip: String,

    #[serde(rename = "remotePort")]
    pub(crate) remote_port: u16,

    #[serde(rename = "linkTest")]
    pub(crate) link_test: u64,
    pub(crate) t3: u64,
    pub(crate) t5: u64,
    pub(crate) t6: u64,
    pub(crate) t7: u64,
    pub(crate) t8: u64,
}

#[derive(Clone, serde::Serialize)]
pub(crate) struct ConnectionEvent {
    id: u64,
    entity: ConnectionEventEntity,
}

impl ConnectionEvent {
    pub(crate) fn new_log_output(
        id: u64,
        time: String,
        level: LogLevel,
        content: String,
        error: Option<String>,
    ) -> Self {
        Self {
            id,
            entity: ConnectionEventEntity::LogOutput {
                time,
                level,
                content,
                error,
            },
        }
    }

    pub(crate) fn new_connection_status_changed(
        id: u64,
        previous: ConnectionStatus,
        current: ConnectionStatus,
    ) -> Self {
        Self {
            id,
            entity: ConnectionEventEntity::ConnectionStatusChanged { previous, current },
        }
    }

    pub(crate) fn new_received_primary_message(
        id: u64,
        time: &chrono::DateTime<Local>,
        message: String,
    ) -> Self {
        Self {
            id,
            entity: ConnectionEventEntity::ReceivedPrimaryMessage {
                time: helper::format_time_h_m_s_3f(&time),
                message,
            },
        }
    }

    pub(crate) fn new_send_message(
        id: u64,
        time: &chrono::DateTime<Local>,
        message: String,
        is_primary: bool,
    ) -> Self {
        Self {
            id,
            entity: ConnectionEventEntity::SendMessage {
                time: helper::format_time_h_m_s_3f(&time),
                message,
                is_primary,
            },
        }
    }
}

#[derive(Clone, serde::Serialize)]
#[serde(tag = "event")]
pub(crate) enum ConnectionEventEntity {
    LogOutput {
        time: String,
        #[serde(with = "serde_loglevel")]
        level: LogLevel,
        content: String,
        error: Option<String>,
    },
    ConnectionStatusChanged {
        #[serde(with = "serde_connection_status")]
        previous: ConnectionStatus,
        #[serde(with = "serde_connection_status")]
        current: ConnectionStatus,
    },
    ReceivedPrimaryMessage {
        time: String,
        /// [`quic-secs-driver::secs2::MessageRef`]
        message: String,
    },
    SendMessage {
        time: String,
        message: String,
        #[serde(rename = "isPrimary")]
        is_primary: bool,
    },
}

// impl ConnectionEventEntity {
//     pub(crate) fn new_log_output() -> Self {
//         Self::LogOutput {
//             time: "2024-12-23".to_string(),
//             level: LogLevel::Debug,
//             content: "test".to_string(),
//             error: None,
//         }
//     }
// }

mod serde_loglevel {
    use quic_secs_driver::enums::LogLevel;
    use serde::{de::Visitor, Deserializer, Serializer};

    pub fn serialize<S: Serializer>(level: &LogLevel, s: S) -> Result<S::Ok, S::Error> {
        s.serialize_u8(match level {
            LogLevel::Trace => 0,
            LogLevel::Debug => 1,
            LogLevel::Info => 2,
            LogLevel::Warn => 3,
            LogLevel::Error => 4,
        })
    }

    #[allow(dead_code)]
    pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<LogLevel, D::Error> {
        struct V;

        impl Visitor<'_> for V {
            type Value = LogLevel;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                formatter.write_str("u8")
            }

            fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                Ok(match v {
                    0 => LogLevel::Trace,
                    1 => LogLevel::Debug,
                    2 => LogLevel::Info,
                    3 => LogLevel::Warn,
                    _ => LogLevel::Error,
                })
            }
        }
        d.deserialize_u8(V)
    }
}

mod serde_connection_status {
    use quic_secs_driver::enums::ConnectionStatus;
    use serde::{de::Visitor, Deserializer, Serializer};

    pub fn serialize<S: Serializer>(status: &ConnectionStatus, s: S) -> Result<S::Ok, S::Error> {
        s.serialize_u8(match status {
            ConnectionStatus::Initial => 0,
            ConnectionStatus::Connecting => 1,
            ConnectionStatus::Connected => 2,
            ConnectionStatus::Selected => 3,
            ConnectionStatus::Deselected => 4,
            ConnectionStatus::Reconnecting => 5,
            ConnectionStatus::Disconnected => 6,
            ConnectionStatus::Shutdown => 7,
        })
    }

    #[allow(dead_code)]
    pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<ConnectionStatus, D::Error> {
        struct V;

        impl Visitor<'_> for V {
            type Value = ConnectionStatus;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                formatter.write_str("u8")
            }

            fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                Ok(match v {
                    0 => ConnectionStatus::Initial,
                    1 => ConnectionStatus::Connecting,
                    2 => ConnectionStatus::Connected,
                    3 => ConnectionStatus::Selected,
                    4 => ConnectionStatus::Deselected,
                    5 => ConnectionStatus::Reconnecting,
                    6 => ConnectionStatus::Disconnected,
                    _ => ConnectionStatus::Shutdown,
                })
            }
        }
        d.deserialize_u8(V)
    }
}

#[derive(Serialize)]
pub(crate) struct ReceivedSecondaryMessage {
    pub(crate) time: String,
    pub(crate) message: MessageWrapperForReceived,
}
